﻿#$language = "Python"
#$interface = "1.0"

'''class for cRNC'''

import os
import sys
import re
from ftplib import FTP

g_local_path = os.path.dirname(os.path.abspath(__file__))
if g_local_path not in sys.path:
    sys.path.insert(0, g_local_path)

import debug
import screen
from const import *

class cRNC():
    name = ''
    build = ''
    corr = ''
    ip = ''
    board_id = {'ICSU': -1, 'OMU': -1}
    def __init__(self, obj, info_enable=False):
        self.obj = obj
        self.log = debug.Log('cRNC: ')
        self.goto_top()
        cRnc_prompt = screen.Prompt(CONST_PROMPT_CRNC, 2, CONST_STYLE_CRNC)
        self.main_crt = screen.Screen(self.obj, cRnc_prompt)
        del cRnc_prompt
        self.board_enabled = self._get_work_board()
        if self.board_enabled:
            self.enter_omu()
            board_prompt = \
                screen.Prompt(CONST_PROMPT_CRNC_BOARD, 1, CONST_STYLE_CRNC)
            self.board_crt = screen.Screen(self.obj, board_prompt)
            del board_prompt
            if info_enable:
                self._get_info()

    def __del__(self):
        del self.log
        del self.main_crt
        if self.board_enabled:
            del self.board_crt

    def _get_work_board(self):
        self.goto_top()
        rspd = self.main_crt.send('ZUSI::WO-EX;\r')
        for line in rspd.splitlines():
            if 'WO-EX' in line:
                if line.strip()[:5] == 'ICSU-':
                    self.board_id['ICSU'] = int(line.strip()[5])
                elif line.strip()[:4] == 'OMU-':
                    self.board_id['OMU'] = int(line.strip()[4])
        
        for key in self.board_id.keys():
            if self.board_id[key] < 0:
                self.log.w('no found {0} in WO-EX.'.format(key))
                return False
        return True

    def _get_info(self):
        self.ip = self.obj.Session.RemoteAddress
        self.name = (self.obj.Session.Path).split('\\').pop()
        self.enter_icsu()
        self.board_crt.send('ZL:P\r')
        self.board_crt.send('ZLP:P,POM\r')
        rsp = self.board_crt.send('ZPS:type,/RUNNING/SW_LEVEL.TXT,0,100\r')
        for var in rsp.splitlines():
            if 'Build' in var:
                self.build = (var.split()[2]).strip('. ')
            elif 'Corr' in var:
                self.corr = (var.split()[2]).strip('. ')
        return None

    def goto_top(self):
        self.obj.Screen.WaitForString(CONST_JUST_WAIT, 1)
        self.obj.Screen.Send('\r')
        for times in range(20):
            if self.obj.Screen.WaitForString(CONST_PROMPT_CRNC, 1):
                break
            else:
                self.obj.Screen.Send('ZEEE;\r')
        return None

    def _enter_board(self, board_name, buffer_enable):
        self.goto_top()
        mml = 'ZDDS:{0},{1}{2};\r'.format(board_name, 
                                          self.board_id[board_name], 
                                          ':BUF' if buffer_enable else '')
        tmp_prompt = screen.Prompt('MAN>')
        for times in range(10):
            rspd = self.main_crt.send(mml, 2, tmp_prompt)
            if 'REMOTE SESSION NOT STARTED' in rspd:
                self.obj.Screen.WaitForString(CONST_JUST_WAIT, 1)
                self.obj.Screen.Send('\r')
                if self.obj.Screen.WaitForString(tmp_prompt.char, 1):
                    break
            else:
                break
        del tmp_prompt
        return None
        
    def enter_icsu(self, buffer_enable=False):
        return self._enter_board('ICSU', buffer_enable)
        
    def enter_omu(self, buffer_enable=False):
        return self._enter_board('OMU', buffer_enable)
    
    def trace_omu_err(self, enter_omu=True):
        if enter_omu:
            self.enter_omu()
        self.obj.Screen.Send('ZGSC:F,,,,E\r')
        err_code = None
        while True:
            rspd = self.obj.Screen.ReadString(['CALLER', '>'], 10)
            match_index = self.obj.Screen.MatchIndex

            for line in rspd.splitlines():
                mat = re.search('USER DATA :  ([0-9A-F]{8})', line)
                if mat is not None:
                    #self.log.w('find match line ' + line, True)
                    if '00002361' != mat.groups()[0]:
                        err_code = mat.groups()[0]
                        #self.log.w('error code is ' + err_code)
                    break
            if match_index != 1: # not find 'CALLER'
                break

        if err_code is not None:
            self.log.w('error code detected: 0x' + err_code)
            self.decode_error(err_code, False)
        return None

    def decode_error(self, err_hex_code, enter_omu=True):
        if enter_omu:
            self.enter_omu()
        self.obj.Screen.Send('ZLP:6,MRS\r')
        self.obj.Screen.WaitForString(CONST_JUST_WAIT, 1)
        rspd = self.board_crt.send('Z6RH:{0}\r'.format(err_hex_code))
        self.log.w('\n'.join(rspd.splitlines()[:2]))
        return None

    def clear_omu_buffer(self, enter_omu=True):
        if enter_omu:
            self.enter_omu()
        for times in range(50):
            rspd = self.board_crt.send('ZOTH\r')
            if 'UNKNOWN COMMAND' in rspd or 'NO MESSAGE' in rspd:
                break
            else:
                debug.sleep(2.0)
        return 0

class cRncFtp():
    '''ftp client for cRNC'''

    ftp = FTP()

    def __init__(self, host, port='21'):
        #self.ftp.set_debuglevel(2)
        self.ftp.connect(host, port)
        self.log = debug.Log('ftp : ')
        self.log.w('connect to ftp ' + host + ':' + port)
        self.login_state = False

    def __del__(self):
        self.login_state = False
        self.log.w('close.')
        del self.log
        if self.login_state:
            self.ftp.quit()
        del self.ftp

    def login(self, user='SYSTEM', passwd='SYSTEM'):
        self.log.w('login ftp', end=' ')
        try:
            self.ftp.login(user, passwd)
        except Exception:
            rslt = False
            self.log.w('failed.', False)
        else:
            rslt = True
            self.log.w('successful.', False)
            self.login_state = True
        finally:
            return rslt

    def download(self, remote_file, local_file):
        if not self.login_state and not self.login():
            return False

        (basename, filename) = os.path.split(local_file) 
        if not os.path.exists(basename):
            self.log.w('local path not exist, mkdir ' + basename)
            os.makedirs(basename)

        self.log.w('start download file.\n' + \
            '{0} ==> {1}'.format(remote_file, local_file))
        file_handler = open(local_file, 'wb')
        rslt = None
        try:
            self.ftp.retrbinary('RETR ' + remote_file, file_handler.write)
        except Exception:
            self.log.w('transfer file failed.')
            rslt = False
        else:
            self.log.w('transfer file successful.')
            rslt = True
        finally:
            file_handler.close()
            debug.sleep(0.5)
            return rslt

    def upload(self, local_file, remote_file):
        if not self.login_state and not self.login():
            return False

        if not os.path.isfile(local_file):
            self.log.w('file ' + local_file + ' does not exist.')
            return False

        self.log.w('start upload file.\n' + \
            '{0} ==> {1}'.format(local_file, remote_file))
        file_handler = open(local_file, 'rb' )
        try:
            self.ftp.storbinary('STOR ' + remote_file, file_handler, 4096)
        except Exception:
            self.log.w('transfer file failed.')
            rslt = False
        else:
            self.log.w('transfer file successful.')
            rslt = True
        finally:
            file_handler.close()
            debug.sleep(0.5)
            return rslt
